#include "ClassTranslator.hpp"
#include "SourceEmitter.hpp"
#include "RootClassInfo.hpp"
#include "RootClassInfoCollection.hpp"
#include "RootClassMethod.hpp"
#include "CPPNetTypeMapper.hpp"
#include "RootClassMethodArg.hpp"
#include "WrapperConfigurationInfo.hpp"
#include "ROOTHelpers.h"
#include "ConverterErrorLog.hpp"
#include "FeatureManager.hpp"

#include "TROOT.h"
#include "TClass.h"

#include <algorithm>
#include <sstream>
#include <fstream>
#include <vector>
#include <iostream>
#include <set>
#include <stdio.h>
#include <stdexcept>

using std::ostringstream;
using std::endl;
using std::cout;
using std::ofstream;
using std::ifstream;
using std::vector;
using std::string;
using std::runtime_error;
using std::set;
using std::for_each;
using std::map;
using std::pair;
using std::string;
using std::getline;
using std::transform;
using std::back_inserter;
using std::inserter;

#ifdef nullptr
#undef nullptr
#endif

ClassTranslator::ClassTranslator(const std::string &base_dir)
	: _base_directory (base_dir)
{
	load_globals();

	_default_header_includes.push_back ("NetArrayTranslator.hpp");
	_default_header_includes.push_back ("VectorObject.hpp");
}

ClassTranslator::~ClassTranslator(void)
{
}

/// Drives the translation of a class
void ClassTranslator::translate(RootClassInfo &class_info)
{
	///
	/// Clean up the class inheritance list. And make sure that everything is well in there. If this fails, then
	/// we need fail hard b/c others might be depending on this class being translated.
	///

	clean_inheritance_list (class_info);
	if (!check_inheritance_list(class_info)) {
		throw new runtime_error ("Class '" + class_info.CPPName() + "' has some bad classes in its inherritance tree");
	}

	///
	/// create the template around the outside
	///

	ostringstream cpp_filename, hpp_filename;
	cpp_filename << _base_directory << "\\" << class_info.NETName() << ".cpp";
	hpp_filename << _base_directory << "\\" << class_info.NETName() << ".hpp";

	SourceEmitter cpp_emitter (cpp_filename.str());
	SourceEmitter hpp_emitter (hpp_filename.str());

	cpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
	hpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
	hpp_emitter() << "#pragma once" << endl;
	cpp_emitter.include_file(class_info.NETName() + ".hpp");

	// HACK Horrible hack: this is because some standalone files require this in order to build (TAttLine, etc.)!
	hpp_emitter.start_line() << "/// Hack to deal with some include files requiring iostream and std to be defined" << endl;
	hpp_emitter.include_file("iostream");
	hpp_emitter.start_line() << "using namespace std;" << endl;

	///
	/// The include file for the ROOT object itself
	///

	hpp_emitter.include_file(class_info.include_filename());

	///
	/// Now, we want every possible method accessible outside the C++ world. The current C++ compiler will make methods
	/// that have raw C++ objects inaccessible outside the library (but accessible within the library). This way, if someone
	/// has to do somethign down and dirty in C++ they can do it without having to hack the code we generate.
	///
	/// Because multiple objects can be defined in one file, we have to make sure all make_public's are issued for the objects
	/// in that one file. Crazyness. So, we write a seperate include file which all headers include for their header.
	/// Note that we write out the seperate file here. Most files will be written once (since the header files contain
	/// only a single object), but some will be written twice. We can do that or make this a lot more complex! :-)
	///

	hpp_emitter.start_line() << "/// Make sure all native objects are accessible outside the boundries of this library/dll" << endl;
	hpp_emitter.include_file(class_info.LibraryName() + "-make_public.hpp");
	_objects_in_library[class_info.LibraryName()].insert(class_info.CPPName());
	_base_directories[class_info.LibraryName()] = _base_directory;

	///
	/// If we have a non-TObject, then we will be needing TClass...
	///

	if (!class_info.InheritsFromTObject() && class_info.CPPName() != "TObject")
	{
		hpp_emitter.include_file("TClass.h");
	}

	///
	/// And the include files for all the interfaces that we will be referencing.
	/// Mark these guys as a dependencies as well, as we will need them in order to
	/// build!
	///
	/// Note that the includes between libraries aren't strictly needed. That is -- if we are building these objects in
	/// different libraries then it really doesn't matter if we do the include (it does matter within the same library,
	/// however). But we treat all objects as the same -- and go overboard with the includes -- because that makes this
	/// bit of code cleaner, and (I hope) doen't slow down the resulting build very much.
	///

	for (unsigned int i = 0; i < class_info.GetDirectInheritedClasses().size(); i++) {
		RootClassInfo &dep_class(RootClassInfoCollection::GetRootClassInfo(class_info.GetDirectInheritedClasses()[i]));
		if (emit_this_header(class_info, dep_class)) {
			hpp_emitter.include_file(dep_class.NETName() + ".hpp");
		}
		if (class_info.LibraryName() != dep_class.LibraryName()) {
			_library_dependencies[class_info.LibraryName()].insert(dep_class.LibraryName());
		}
	}

	set<string> referenced_classes;
	copy (class_info.GetReferencedClasses().begin(), class_info.GetReferencedClasses().end(),
		inserter(referenced_classes, referenced_classes.begin()));
	auto featureClasses = FeatureManager::GetFeaturesFor(class_info).get_additional_root_class_references(class_info);
	copy (featureClasses.begin(), featureClasses.end(), inserter(referenced_classes, referenced_classes.begin()));
	vector<string> v_referenced_classes (referenced_classes.begin(), referenced_classes.end());

	for (unsigned int i = 0; i < v_referenced_classes.size(); i++) {
		RootClassInfo &dep_class(RootClassInfoCollection::GetRootClassInfo(v_referenced_classes[i]));
		if (CPPNetTypeMapper::instance()->has_mapping(dep_class.CPPName())) {
			if (emit_this_header(class_info, dep_class)) {
				cpp_emitter.include_file(dep_class.NETName() + ".hpp");
			} else {
				cpp_emitter.include_file(dep_class.include_filename());
			}
			if (class_info.LibraryName() != dep_class.LibraryName()) {
				_library_dependencies[class_info.LibraryName()].insert(dep_class.LibraryName());
			}
		}
	}

	for (unsigned int i = 0; i < class_info.GetReferencedEnums().size(); i++) {
		RootEnum dep_enum (class_info.GetReferencedEnums()[i]);
		if (CPPNetTypeMapper::instance()->has_mapping(dep_enum.NameQualified())) {
			if (!emit_this_enum(class_info, dep_enum)) {
				cpp_emitter.include_file(dep_enum.include_filename());
			}
		}
	}

	///
	/// Always enable the referencing of arrays
	///

	emit_hpp_headers(hpp_emitter);

	///
	/// We use exceptions...
	///

	cpp_emitter.include_file("stdexcept");

	///
	/// Enum's can't be forward declared -- they have to be included... If they are class enums, however, then
	/// they should just come in. If they are in other libraries, then they will be pulled in with the reference.
	/// The trick comes b/c if they are defined in the library we are working on right now, then they will have to
	/// be included. Ugh.
	///

	for (unsigned int i = 0; i < class_info.GetReferencedEnums().size(); i++) {
		RootEnum dep_enum (class_info.GetReferencedEnums()[i]);
		if (CPPNetTypeMapper::instance()->has_mapping(dep_enum.NameQualified())) {
			if (!dep_enum.IsClassDefined()) {
				if (emit_this_enum(class_info, dep_enum)) {
					hpp_emitter.include_file(dep_enum.NameUnqualified() + ".hpp");
				}
			} else {
				if (dep_enum.LibraryName() == class_info.LibraryName()) {
					if (dep_enum.NETClassName() != class_info.NETName()) {
						hpp_emitter.include_file(dep_enum.NETClassName() + ".hpp");
					}
				}
			}
		}
	}

	///
	/// Put everything in a ROOT namespace to keep it clean...
	///

	hpp_emitter.start_namespace ("ROOTNET");
	cpp_emitter.start_namespace ("ROOTNET");

	///
	/// Forward declare the various .net classes we might be referencing in the
	/// header...
	///

	for (unsigned int i = 0; i < class_info.GetReferencedClasses().size(); i++) {
		string referenced_classname = class_info.GetReferencedClasses()[i];
		if (CPPNetTypeMapper::instance()->has_mapping(referenced_classname)) {
			hpp_emitter.forward_class_reference(RootClassInfoCollection::GetRootClassInfo(referenced_classname).NETName());
		}
	}


	///
	/// Generate the interface and the actual class
	///

	generate_interface (class_info, hpp_emitter);
	generate_class_methods (class_info, cpp_emitter);
	generate_interface_static_methods (class_info, cpp_emitter);
	generate_class_header (class_info, hpp_emitter);

	///
	/// Now the full on object.
	///

	hpp_emitter.brace_close();
	cpp_emitter.brace_close();

	///
	/// Close everything up so we can get on with things
	///

	hpp_emitter.close();
	cpp_emitter.close();
}

void ClassTranslator::emit_hpp_headers(SourceEmitter &hpp_emitter)
{
	for (int i = 0; i < _default_header_includes.size(); i++) {
		hpp_emitter.include_file(_default_header_includes[i]);
	}
}


/// Helper class to dump out the make public files.
class write_out_make_public
{
public:
	inline write_out_make_public (const map<string, string> base_directories)
		: _base_directory(base_directories)
	{
	}
	void operator() (const pair<string, set<string> > &item);
private:
	const map<string, string> _base_directory;
};

///
/// Write out all the make-public statements and forward declare all the classes. We do this to uniformly expose all the
/// various items to other libraries.
///
void ClassTranslator::finalize_make_publics()
{
	for_each (_objects_in_library.begin(), _objects_in_library.end(),
		write_out_make_public(_base_directories));
}
void write_out_make_public::operator ()(const std::pair<string,set<string> > &item)
{
	string library_name (item.first);
	set<string> all_objects_set (item.second);

	ostringstream make_public_filename;
	map<string, string>::const_iterator dir_loc = _base_directory.find(library_name);
	if (dir_loc == _base_directory.end()) {
		throw runtime_error ("Unable to find base directory for library " + library_name);
	}
	make_public_filename << dir_loc->second << "\\" << library_name << "-make_public.hpp";

	SourceEmitter make_public_header (make_public_filename.str());
	make_public_header.start_line() << "#pragma once" << endl;
	make_public_header.start_line() << "// List of the objects defined in this library, tagged with make_public" << endl;
	vector<string> all_objects(all_objects_set.begin(), all_objects_set.end());
	for (unsigned int i = 0; i < all_objects.size(); i++) {
		make_public_header.start_line() << "class " << all_objects[i] << ";" << endl;
		make_public_header.start_line() << "#pragma make_public(" << all_objects[i] << ")" << endl;
	}
	make_public_header.close();
}

namespace {
	/// Indexers -- using the [] operators in C++ -- are a tried and true way of getting and setting
	/// elements inside an array like object. .NET supports this in the form of "indexers" -- but
	/// they require a "get" and a "set" method, and you don't use a reference. So we have to sort
	/// through the C++ code and see if we can tease all that information out.

	/// Store info about the operator[] pairs that are out there.
	class CPPIndexerInfo
	{
	public:
		/// Translators to represent the C++/.NET arguments.
		const CPPNetTypeMapper::TypeTranslator *_index_type;
		const CPPNetTypeMapper::TypeTranslator * _return_type;

		/// The method this is based on
		const RootClassMethod *_method;

		/// True if this has a get and a set (you can set the internal value). You can always get it...
		bool _is_setter;

		inline CPPIndexerInfo (void)
			: _is_setter(false), _index_type(0), _return_type(0)
		{}

	};

	/// Helper task to convert a map into a vector. Just makes code below
	/// prettier.
	template<class C>
	class copy_map_target_t
	{
	public:
		template<class I>
		inline void operator() (const pair<I,C> &item)
		{
			_vector.push_back(item.second);
		}
		inline const vector<C> &as_vector(void) const
		{
			return _vector;
		}
	private:
		vector<C> _vector;
	};

	/// Given a list of indexers, try to find all the ones that match up.
	vector<CPPIndexerInfo> SortIndexers(const vector<RootClassMethod> &index_list)
	{
		map<string, CPPIndexerInfo> result_map;

		for (int i = 0; i < index_list.size(); i++) {
			const RootClassMethod &method(index_list[i]);

			/// Figure out what this guy is
			string return_type = method.return_type();
			if (method.arguments().size() != 1) {
				ConverterErrorLog::log_type_error(method.ClassOfMethodDefinition(),
					"Indexer with return type " + return_type + " does not have a single argument!");
				continue;
			}
			const string index_argument = method.arguments()[0].NETInterfaceTypeName();

			/// Look for clues in the return type to see what the ROOT Dev team wanted to do with this.
			bool has_const = false;
			bool has_reference = false;
			bool is_abs_class = false;

			if (return_type.find("const ") == 0) {
				has_const = true;
			}
			int ref_index = return_type.find("&");
			if (ref_index != return_type.npos) {
				//return_type = return_type.substr(0,ref_index) + return_type.substr(ref_index+1);
				has_reference = true;
			}

			const CPPNetTypeMapper::TypeTranslator *tt = CPPNetTypeMapper::instance()->get_translator_from_cpp(return_type);

			TClass *return_type_class = gROOT->GetClass(tt->cpp_core_typename().c_str());
			if (return_type_class != 0) {
				is_abs_class = (return_type_class->Property() & kIsAbstract) != 0;
			}

			/// Given that, is this a getter or a setter? If the return is const, then this
			/// is a getter, no matter if it is a reference. Otherwise, a reference operator means
			/// it was a setter.
			bool is_setter = has_reference && !has_const && !is_abs_class;

			/// Now, lets log this puppy in. Error if return types are different!
			if (result_map.find(index_argument) == result_map.end()) {
				CPPIndexerInfo temp;
				temp._index_type = CPPNetTypeMapper::instance()->get_translator_from_cpp(method.arguments()[0].CPPTypeName());
				temp._return_type = tt;
				temp._method = &method;
				result_map[index_argument] = temp;
			} else {
				if (result_map[index_argument]._return_type->cpp_core_typename() != tt->cpp_core_typename()) {
					is_setter = false;
					ConverterErrorLog::log_type_error(method.ClassOfMethodDefinition(), "Indexer with argument '" + index_argument + "' has more than one return type ('"
						+ return_type + "', '" + result_map[index_argument]._return_type->cpp_typename() + "')");
				}
			}
			if (is_setter) {
				result_map[index_argument]._is_setter = true;
			}
		}

		/// Turn it into a vector to return

		vector<CPPIndexerInfo> result = for_each(result_map.begin(), result_map.end(),
			copy_map_target_t<CPPIndexerInfo>()).as_vector();

		return result;
	}

	///
	/// Returns a list of deep non-inherrited classes.
	///
	set<string> GetNonInherritedClasses(const RootClassInfo &info)
	{
		auto &superClasses (info.GetDirectInheritedClasses());
		auto directSuper (info.GetBestClassToInherrit());
		set<string> inh_classes;
		for_each(superClasses.begin(), superClasses.end(), [&] (const string &cname)
		{
			if (directSuper != cname) {
				auto &classInfo (RootClassInfoCollection::GetRootClassInfo(cname));
				auto &deepClasses (classInfo.GetInheritedClassesDeep());
				copy(deepClasses.begin(), deepClasses.end(), inserter(inh_classes, inh_classes.begin()));
				inh_classes.insert(cname);
			}
		});
		inh_classes.insert(info.CPPName());

		return inh_classes;
	}

	// See if this property should be emitted in the class that is being worked on. The
	// list of classes that aren't in the direct inherritance path is passed to figure this out.
	bool propertyShouldBeEmitted (const RootClassProperty &prop, const set<string> &nonInheritedClasses)
	{
		bool getter_good = prop.isGetter() && nonInheritedClasses.find(prop.getter_method()->ClassOfMethodDefinition()) != nonInheritedClasses.end();
		bool setter_good = prop.isSetter() && nonInheritedClasses.find(prop.setter_method()->ClassOfMethodDefinition()) != nonInheritedClasses.end();

		return getter_good || setter_good;
	}
}

class emit_enum_as_static {
public:
	inline emit_enum_as_static (SourceEmitter &emitter)
		: _emitter(emitter)
	{}
	inline void operator() (const pair<string, unsigned int> &item)
	{
		_emitter.start_line() << "static const unsigned int " << item.first << " = " << item.second << ";" << endl;
	}
private:
	SourceEmitter &_emitter;
};

///
/// Helper functiont to write out static enum defs
///
void write_header_enum_standard (const RootEnum &einfo, SourceEmitter &emitter, bool is_global = false)
{
	if (is_global) {
		emitter.start_line() << "public ";
	} else {
		emitter.start_line();
	}
	emitter() << "enum class ";
	if (einfo.NameUnqualified() == "") {
		emitter() << "EClassConstants";
	} else {
		emitter() << einfo.NameUnqualified();
	}
	emitter() << endl;

	emitter.brace_open();
	for (int en = 0; en < einfo.values().size(); en++) {
		emitter.start_line() << einfo.values()[en].first << " = " << einfo.values()[en].second;
		if (en != einfo.values().size()-1) {
			emitter() << ",";
		}
		emitter() << endl;
	}
	emitter.brace_close(true);
}

///
/// Write the enum specs
///
void write_header_enums (RootClassInfo &class_info, SourceEmitter &emitter, bool all_standard_format)
{
	const vector<RootEnum> &class_enums (class_info.GetClassEnums());
	for (unsigned int i = 0; i < class_enums.size(); i++) {
		/// If they are not a named enum, then simulate them with a set of constants
		if (class_enums[i].NameUnqualified() == "" && !all_standard_format) {
			std::for_each (class_enums[i].values().begin(), class_enums[i].values().end(),
				emit_enum_as_static (emitter));
		} else {
			write_header_enum_standard (class_enums[i], emitter);
		}
	}

}

///
/// Generate the interface specification
///
void ClassTranslator::generate_interface (RootClassInfo &class_info, SourceEmitter &emitter)
{

	emitter.start_namespace("Interface");

	///
	/// Add forward references for the interfaces
	///

	for (unsigned int i = 0; i < class_info.GetReferencedClasses().size(); i++) {
		string referenced_classname = class_info.GetReferencedClasses()[i];
		if (CPPNetTypeMapper::instance()->has_mapping(referenced_classname)) {
			emitter.forward_interface_reference(RootClassInfoCollection::GetRootClassInfo(referenced_classname).NETName());
		}
	}

	///
	/// And now the interface itself.
	///

	auto class_features = FeatureManager::GetFeaturesFor(class_info);

	emitter.start_line() << "public interface class " << class_info.NETName() << endl;

	///
	/// The interface can inherrit from a number of places...
	///

	const vector<string> &inherited_classes (class_info.GetDirectInheritedClasses());
	set<string> inherited_interfaces;
	transform (inherited_classes.begin(), inherited_classes.end(),
		inserter(inherited_interfaces, inherited_interfaces.begin()),
		[] (const string &s) { return "ROOTNET::Interface::" + RootClassInfoCollection::GetRootClassInfo(s).NETName(); });
	auto others = class_features.get_additional_interfaces(class_info);
	copy (others.begin(), others.end(), inserter(inherited_interfaces, inherited_interfaces.begin()));

	if (inherited_interfaces.size() > 0) {
		emitter.start_line() << "  : ";
		bool one = false;
		for_each (inherited_interfaces.begin(), inherited_interfaces.end(),
			[&emitter, &one] (const string &s) {
				if (one)
					emitter() << ", ";
				one = true;
				emitter() << s;
		});

		emitter() << endl;
	}

	emitter.brace_open();

	///
	/// The special prototype for accessing the raw objects...
	///

	emitter.start_line() << "::" << class_info.CPPName() << " *CPP_Instance_" << class_info.CPPName() << "(void);" << endl;

	///
	/// Special prototype to set-to-null the instance object when ROOT (or similar) makes it go away, or to
	/// delete it.
	///

	emitter.start_line() << "void SetNull (void);" << endl;
	emitter.start_line() << "void DeleteHeldObject (void);" << endl;
	emitter.start_line() << "void DropObjectFromTables (void);" << endl;
	emitter.start_line() << "int GetRawCPPPointer(void);" << endl;

	///
	/// Put in all class defined enums now. They have to go early b/c they have to be declared
	/// when they are defined.
	///

	write_header_enums (class_info, emitter, true);

	///
	/// List all the prototypes for the class.
	/// TODO: This comes back clean, and needs to be fixed so that the fact we couldn't do a bunch of
	///       prototypes was because they weren't translatable needs to get recoreded! :-)
	///

	set<string> already_done_headers;
	vector<RootClassMethod> indexerOperators;
	auto inh_classes(GetNonInherritedClasses(class_info));

	const vector<RootClassMethod> class_protos (class_info.GetAllPrototypesForThisClass(true));
	for (unsigned int i = 0; i < class_protos.size(); i++) {
		const RootClassMethod &method = class_protos[i];

		// Make sure what we are looking at should be in here!
		if (inh_classes.find(method.ClassOfMethodDefinition()) == inh_classes.end())
			continue;

		/// If it is an indexer, keep it for later
		if (method.IsIndexer()) {
			indexerOperators.push_back(method);
		}

		if (!method.IsGoodForInterface()) {
			continue;
		}

		/// Generate and write out the header.

		try {
			if (!method.has_return_value() || !method.get_return_type_translator()->is_reference_to_object()) {
				string n_header (method.generate_normalized_method_header());

				if (already_done_headers.find(n_header) == already_done_headers.end()) {
					already_done_headers.insert(n_header);
					if (method.IsStatic()) {
						emitter.start_line() << "static ";
					}
					emitter.start_line() << method.generate_method_header() << ";" << endl;
				}
			}
		} catch (runtime_error &e)
		{
			cout << "  interface translation failed (" << method.CPPName() << "): " << e.what() << endl;
		}
	}

	///
	/// Do the properties for this object.
	///

	const vector<RootClassProperty> &properties (class_info.GetProperties());
	for (vector<RootClassProperty>::const_iterator itr = properties.begin(); itr != properties.end(); itr++) {
		// Make sure at least one of these guys is defined in this thing
		if (!propertyShouldBeEmitted(*itr, inh_classes))
			continue;

		emitter.start_line();
		if (itr->isStatic())
			emitter() << "static ";
		emitter() << "property " << itr->property_type() << " " << itr->name() << " {" << endl;
		if (itr->isGetter()) {
			emitter.start_line() << "  " << itr->property_type() << " get ();" << endl;
		}
		if (itr->isSetter()) {
			emitter.start_line() << "  void set (" << itr->property_type() << " value);" << endl;
		}
		emitter.start_line() << "}" << endl;
	}

	///
	/// Do the fields for this object
	///

	auto &fields (class_info.GetAllDataFields(true));
	for (int i = 0; i < fields.size(); i++) {
		const RootClassField &f(fields[i]);
		emitter.start_line() << "property " << f.NETType() << " " << f.NETName() << " {" << endl;
		if (f.GetterOK()) {
			emitter.start_line() << "  " << f.NETType() << " get ();" << endl;
		}
		if (f.SetterOK()) {
			emitter.start_line() << "  void set (" << f.NETType() << " value);" << endl;
		}
		emitter.start_line() << "}" << endl;
	}

	///
	/// Put in a reference to the indexers so others can do the array lookups. :-)
	///

	vector<CPPIndexerInfo> indexers (SortIndexers(indexerOperators));
	for (unsigned int i = 0; i < indexers.size(); i++) {

		CPPIndexerInfo &info (indexers[i]);
		if (inh_classes.find(info._method->ClassOfMethodDefinition()) == inh_classes.end())
			continue;

		emitter.start_line() << "property " << info._return_type->net_return_type_name() << " default[" << info._index_type->net_interface_name() << "] {" << endl;
		emitter.start_line() << "  " << info._return_type->net_return_type_name() << " get (" << info._index_type->net_interface_name() << " index);" << endl;
		if (info._is_setter) {
			emitter.start_line() << "  void set (" << info._index_type->net_interface_name() << " index, " << info._return_type->net_return_type_name() << " value);" << endl;
		}
		emitter.start_line() << "}" << endl;
	}

	///
	/// Great. Now we can close it out
	///

	emitter.brace_close(true); // End of class definition
	emitter.brace_close(); // End of namespace
}

///
/// Generate the interface static methods.
///
void ClassTranslator::generate_interface_static_methods (RootClassInfo &class_info, SourceEmitter &emitter)
{

	emitter.start_namespace("Interface");

	///
	/// Work only on static methods here...
	///

	auto inh_classes(GetNonInherritedClasses(class_info));
	set<string> already_done_headers;
	const vector<RootClassMethod> &protos (class_info.GetAllPrototypesForThisClass(true));
	for (unsigned int i = 0; i < protos.size(); i++) {
		const RootClassMethod &method = protos[i];
		if (!method.IsStatic() || !method.IsGoodForInterface()) {
			continue;
		}
		if (inh_classes.find(method.ClassOfMethodDefinition()) == inh_classes.end())
			continue;

		/// Generate and write out the header.

		try {
			string n_header (method.generate_normalized_method_header());

			if (already_done_headers.find(n_header) == already_done_headers.end()) {
				already_done_headers.insert(n_header);
				emitter.start_line() << method.generate_method_header(true) << "" << endl;
			} else {
				continue;
			}
		} catch (runtime_error &e)
		{
			cout << "  interface translation failed (" << method.CPPName() << "): " << e.what() << endl;
		}

		///
		/// Generate a call to the static method of the actual object!
		///

		emitter.brace_open();

		emitter.start_line();
		if (method.has_return_value()) {
			emitter() << "return ";
		}
		emitter() << "ROOTNET::" << class_info.NETName() << "::" << method.NETName() << "(";
		for (unsigned int i = 0; i < method.arguments().size(); i++) {
			if (i > 0) {
				emitter() << ", ";
			}
			emitter() << method.arguments()[i].get_argname();
		}
		emitter() << ");" << endl;
		emitter.brace_close();
	}

	///
	/// Next, do the properties for the interface that have been declared static.
	///

	const vector<RootClassProperty> &properties (class_info.GetProperties());
	for (vector<RootClassProperty>::const_iterator itr = properties.begin(); itr != properties.end(); itr++) {
		if (!itr->isStatic())
			continue;

		// Make sure at least one of these guys is defined in this thing
		if (!propertyShouldBeEmitted(*itr, inh_classes))
			continue;

		if (itr->isGetter()) {
			emitter.start_line() << itr->property_type() << " " << class_info.NETName() << "::" << itr->name() << "::get ()" << endl;
			emitter.brace_open();
			emit_function_body(*(itr->getter_method()), class_info, emitter);
			emitter.brace_close();
		}
		if (itr->isSetter()) {
			emitter.start_line() << "void " << class_info.NETName() << "::" << itr->name() << "::set (" << itr->property_type()
				<< " " << itr->setter_method()->arguments()[0].get_argname()  << ")" << endl;
			emitter.brace_open();
			emit_function_body(*(itr->setter_method()), class_info, emitter);
			emitter.brace_close();
		}
	}


	///
	/// Great. Now we can close it out
	///

	emitter.brace_close(); // End of namespace
}

namespace {
	// Emit the method headers for an operator. This is different than the classic one because
	// it is static - so we have to have both guys as operators.
	// We reverse the order so that as long as their is one 
	vector<string> generate_operator_header (const RootClassMethod &method, bool emit_class_method_name = false)
	{
		auto mainObj = CPPNetTypeMapper::instance()->get_translator_from_cpp(method.OwnerClass().CPPName());
		auto base_arg (mainObj->net_typename() + " base_obj_a1");

		string args (method.generate_normalized_method_arguments(true));
		string args_sep = ", ";
		if (args.length() == 0)
			args_sep = "";

		//
		// We reverse the arguments so that you can something like "5 * obj" and "obj * 5".
		// However, if it is "obj * obj" and both obj's are same, then we can't do this because
		// we'll end up with ambigous operators.
		//

		int max_count = 2;
		const RootClassInfo &cInfo (method.OwnerClass());
		if (method.arguments().size() == 0)
			max_count = 1;
		if (method.arguments().size() > 0 && method.arguments()[0].RawCPPTypeName() == cInfo.CPPName())
			max_count = 1;

		//
		// Emit everything
		//

		vector<string> result;
		for (int count = 0; count < max_count; count++) {
			ostringstream header;
			if (method.has_return_value()) {
				header << method.get_return_type_translator()->net_typename() << " ";
			} else {
				header << "void ";
			}

			if (emit_class_method_name) {
				header << method.OwnerClass().NETName() << "::";
			}

			header << method.NETName()
				<< "(";

			if (count == 0) {
				header << base_arg << args_sep << args;
			} else {
				header << args << args_sep << base_arg;
			}
			header << ")";
			result.push_back(header.str());
		}
		return result;
	}
}

///
/// Generate the header for the class.
///
void ClassTranslator::generate_class_header (RootClassInfo &info, SourceEmitter &emitter)
{
	///
	/// Emit the class declaration, along with the inherritance path.
	///

	emitter.start_line() << "public ref class " << info.NETName() << endl;

	auto bestClassToInherrit (info.GetBestClassToInherrit());
	if (bestClassToInherrit.size() == 0) {
		emitter.start_line() << "  : ROOTNET::Utility::ROOTDOTNETBaseTObject," << endl;
	} else {
		auto &infoInherrit (RootClassInfoCollection::GetRootClassInfo(bestClassToInherrit));
		emitter.start_line() << "  : ROOTNET::" << infoInherrit.NETName() << "," << endl;
	}
	emitter.start_line() << "    ROOTNET::Interface::" << info.NETName() << endl;
	emitter.brace_open();

	//
	// Do protected
	//

	emitter.start_line() << "protected:" << endl;
	emitter.start_line() << "  void SetInstance (::" << info.CPPName() << "* instance) {" << endl;
	emitter.start_line() << "    _instance = instance;" << endl;
	if (bestClassToInherrit.size() != 0)
		emitter.start_line() << "    N" << bestClassToInherrit << "::SetInstance (instance);" << endl;
	emitter.start_line() << "}" << endl;

	///
	/// Hold onto the C++ pointer!
	///

	emitter.start_line() << "private:" << endl;
	emitter.start_line() << "::" << info.CPPName() << " *_instance;" << endl;
	emitter() << endl;

	///
	/// Give us some access to the C++ pointers for all inherited classes...
	/// When dealing with inherritance make sure that we do the CPP_Instance's 
	/// correctly.
	///

	auto inh_classes(GetNonInherritedClasses(info));
	for_each(inh_classes.begin(), inh_classes.end(), [&] (const string &cls)
	{
		if (cls.find("<") == cls.npos) {
			emitter.start_line() << "public:" << endl;
			emitter.start_line() << "virtual ::" << cls << " *CPP_Instance_" << cls << "(void)" << endl;
			emitter.brace_open();
			emitter.start_line() << "  return _instance;" << endl;
			emitter.brace_close();
		}
	});

	///
	/// And a ctor that can start from a pointer
	///

	emitter.start_line() << info.NETName() << "(::" << info.CPPName() << " *instance);" << endl;

	emitter.start_line() << info.NETName() << "(::" << info.CPPName() << " &instance);" << endl;

	//
	// Common method to get out the TObject and void pointer.
	//

	emitter.start_line() << "protected:" << endl;
	if (info.InheritsFromTObject() || info.CPPName() == "TObject") {
		emitter.start_line() << "virtual ::TObject *GetTObjectPointer (void) override { return _instance; }" << endl;
		emitter.start_line() << "virtual ::TClass *GetAssociatedTClassInfo (void) override" << endl;
		emitter.brace_open();
		emitter.start_line() << "if (_instance == nullptr)" << endl;
		emitter.start_line() << "  return nullptr;" << endl;
		emitter.start_line() << "return _instance->IsA();" << endl;
		emitter.brace_close();
	} else {
		emitter.start_line() << "virtual ::TObject *GetTObjectPointer (void) override { return (::TObject*) 0; }" << endl;
		emitter.start_line() << "virtual ::TClass *GetAssociatedTClassInfo (void) override" << endl;
		emitter.brace_open();
		emitter.start_line() << "return TClass::GetClass(\"" << info.CPPName() << "\");" << endl;
		emitter.brace_close();
	}
	emitter.start_line() << "virtual void *GetVoidPointer (void) override { return _instance; }" << endl;

	///
	/// And a guy to set the thing to null
	///

	emitter.start_line() << "public:" << endl;
	emitter.start_line() << "virtual void SetNull (void) override { _instance = 0; SetNullReason(ROOTNET::Utility::ReasonPointerNullEnum::kSetNullCalled);}" << endl;
	emitter.start_line() << "virtual void DropObjectFromTables (void) override;" << endl;

	///
	/// Allow for deleting, as long as we can get at the dtor!
	///

	if (info.CanDelete()) {
		emitter.start_line() << "virtual void DeleteHeldObject (void) override { delete _instance; _instance = 0;SetNullReason(ROOTNET::Utility::ReasonPointerNullEnum::kObjectDeleted);}" << endl;
	} else {
		emitter.start_line() << "virtual void DeleteHeldObject (void) override {_instance = 0;SetNullReason(ROOTNET::Utility::ReasonPointerNullEnum::kObjectNotDeleted);}" << endl;
	}

	///
	/// Allow one to get a hold of the raw pointer. Yes, this is evil. But sometimes it is necessary.
	/// This will break if built in x64 I would guess. :-(
	///

	emitter.start_line() << "virtual int GetRawCPPPointer(void)";
	if (bestClassToInherrit.size() > 0)
		emitter() << " new";
	emitter() << " {return (int) _instance;}" << endl;

	///
	/// Emit all the method signatures...
	///

	set<string> written_methods;
	vector<RootClassMethod> arrayOperators;
	vector<RootClassMethod> mathOperators;
	const vector<RootClassMethod> &class_protos(info.GetAllPrototypesForThisClass(true));
	for (unsigned int i = 0; i < class_protos.size(); i++) {
		const RootClassMethod &method = class_protos[i];

		//
		// We only want to implement this class if it is in one of the classes we have implemented as an
		// interface.
		//

		if (inh_classes.find(method.ClassOfMethodDefinition()) == inh_classes.end())
			continue;

		//
		// Accumulate the various indexers, or if there is a problem with this method, etc.
		//

		if (method.IsIndexer()) {
			arrayOperators.push_back(method);
			continue;
		}
		if (!method.IsGoodForClass()) {
			continue;
		}

		if (method.IsMathOperator())
		{
			mathOperators.push_back(method);
			continue;
		}

		try {
			if (method.IsCtor()) {
				string n_header = method.generate_normalized_method_header();
				if (written_methods.find(n_header) != written_methods.end()) {
					continue;
				}
				written_methods.insert(n_header);

				emitter.start_line() << method.generate_method_header() << ";" << endl;
			} else {
				/// We don't deal with references in returns yet...
				if (!method.has_return_value() || !method.get_return_type_translator()->is_reference_to_object()) {
					string n_header = method.generate_normalized_method_header();
					if (written_methods.find(n_header) != written_methods.end()) {
						ConverterErrorLog::log_type_error(method.return_type(), "Don't do references as returns from methods yet");
						continue;
					}
					written_methods.insert(n_header);

					///
					/// The header should have everything in it, and since it is implementing something in
					/// the interface, we had better mark it virtual. Unless it is static, in which case it only
					/// exists here.
					///

					emitter.start_line();
					if (method.IsStatic()) {
						emitter() << "static ";
					} else {
						emitter() << "virtual ";
					}
					emitter() << method.generate_method_header();
					if (method.IsDefaultOverride())
						emitter() << " override";
					emitter() << ";" << endl;
				}
			}
		} catch (runtime_error &e) {
			cout << "  translation failed (" << method.CPPName() << "): " << e.what() << endl;
			continue;
		}
	}

	//
	// Do the math operators. Here we need to generate static versions so C# knows what to do.
	//

	emitter.start_line() << "// Math Operators for C#-like languages" << endl;
	for (vector<RootClassMethod>::const_iterator itr = mathOperators.begin(); itr != mathOperators.end(); itr++) {
		auto headers (generate_operator_header (*itr));
		for (vector<string>::const_iterator itr_h = headers.begin(); itr_h != headers.end(); itr_h++) {
			emitter.start_line() << "static ";
			emitter() << *itr_h << ";" << endl;
		}
	}

	///
	/// Do the properties for this object.
	///

	const vector<RootClassProperty> &properties (info.GetProperties());
	for (vector<RootClassProperty>::const_iterator itr = properties.begin(); itr != properties.end(); itr++) {

		// Make sure at least one of these guys is defined in this thing
		if (!propertyShouldBeEmitted(*itr, inh_classes))
			continue;

		// Emit the proper getters and setters

		emitter.start_line();
		if (itr->isStatic())
			emitter() << "static ";
		emitter() << "property " << itr->property_type() << " " << itr->name() << " {" << endl;

		if (itr->isGetter()) {
			emitter.start_line() << "  ";
			if (!itr->isStatic())
				emitter() << "virtual ";
			emitter() << itr->property_type() << " get ()";
			if (itr->getter_method()->IsDefaultOverride())
				emitter() << " new";
			emitter() << ";" << endl;
		}

		if (itr->isSetter()) {
			emitter.start_line() << "  ";
			if (!itr->isStatic())
				emitter() << "virtual ";
			emitter() << "void set (" << itr->property_type() << " value)";
			if (itr->setter_method()->IsDefaultOverride())
				emitter() << " new";
			emitter() << ";" << endl;
		}
		emitter.start_line() << "}" << endl;
	}

	///
	/// Do the fields for this object
	///

	auto &fields (info.GetAllDataFields(true));
	for (int i = 0; i < fields.size(); i++) {
		const RootClassField &f(fields[i]);

		// Make sure this field is in the proper class!
		if (inh_classes.find(f.ClassOfFieldDefinition()) == inh_classes.end())
			continue;

		emitter.start_line() << "property " << f.NETType() << " " << f.NETName() << " {" << endl;
		if (f.GetterOK()) {
			emitter.start_line() << "  virtual " << f.NETType() << " get ();" << endl;
		}
		if (f.SetterOK()) {
			emitter.start_line() << "  virtual void set (" << f.NETType() << " value);" << endl;
		}
		emitter.start_line() << "}" << endl;
	}

	///
	/// Next, put in a reference to the indexers so others can do the array lookups. :-)
	///

	vector<CPPIndexerInfo> indexers (SortIndexers(arrayOperators));
	for (unsigned int i = 0; i < indexers.size(); i++) {
		CPPIndexerInfo &info (indexers[i]);

		if (inh_classes.find(info._method->ClassOfMethodDefinition()) == inh_classes.end())
			continue;

		emitter.start_line() << "property " << info._return_type->net_return_type_name() << " default[" << info._index_type->net_interface_name() << "] {" << endl;
		emitter.start_line() << "  virtual " << info._return_type->net_return_type_name() << " get (" << info._index_type->net_interface_name() << " index)";
		if (info._method->IsDefaultOverride())
			emitter() << " override";
		emitter() << ";" << endl;

		if (info._is_setter) {
			emitter.start_line() << "  virtual void set (" << info._index_type->net_interface_name() << " index, " << info._return_type->net_return_type_name() << " value)";
			if (info._method->IsDefaultOverride())
				emitter() << " override";
			emitter() << ";" << endl;
		}
		emitter.start_line() << "}" << endl;
	}

	///
	/// If there are any global variables, we need to emit those as well!
	/// There is something funny (and illegal) about calling the GetBsetObject from the static decl. Instead, we have to build a dummy
	/// routine first (or we get compiler errors).
	///
	/// Make the accessor a property accessor so that we always call the Load. The reason for this is to make sure that we
	/// always get the latest version. For example, gDirectory is often switching and we will have to be able to deal with that
	/// here.
	///
	/// We take a slightly different route for a non-TObject.
	///

	if (type_has_globals(info.CPPName())) {
		auto &globals (list_of_globals_of_type(info.CPPName()));
		for (unsigned int i = 0; i < globals.size(); i++) {
			string loadCall;
			if (info.InheritsFromTObject()) {
				loadCall = "ROOTNET::Utility::ROOTObjectServices::GetBestObject<Interface::" + info.NETName() + "^>(::" + globals[i].Name() + ")";
			} else {
				loadCall = "gcnew " + info.NETName() + "(::" + globals[i].Name() + ")";
			}

			///
			/// Now create the static property accessor
			///

			string interfaceName = "Interface::" + info.NETName() + " ^";
			emitter.start_line() << "static property " << interfaceName << globals[i].Name() << endl;
			emitter.brace_open();
			emitter.start_line() << interfaceName << " get() { return " << loadCall << "; }" << endl;
			emitter.brace_close();
		}
	}

	///
	/// If there are any feature methods, now is the time!
	///

	FeatureManager::GetFeaturesFor(info).emit_header_method_definitions(info, emitter);

	///
	/// Done with the class decl!
	///

	emitter.brace_close(true);

}

///
/// Register this class with the monitor -- but only if it comes from TObject (because otherwise it isn't
/// plugged into any of the framework).
///
void ClassTranslator::emit_registration (const RootClassInfo &info, SourceEmitter &emitter, bool we_own)
{
	if (info.CPPName() == "TObject" || info.InheritsFromTObject()) {
		emitter.start_line() << "ROOTNET::Utility::ROOTObjectManager::instance()->RegisterObject (_instance, this);" << endl;
		if (we_own) {
			emitter.start_line() << "_owner = true;" << endl;
		} else {
			emitter.start_line() << "_owner = false;" << endl;
		}
	}
}

namespace {
	/// Translate a single type from .NET to CPP. Return the variable name
	/// you should use in your code.
	string emit_translation_net_cpp (const string &var_name, // Name in .net world
		const CPPNetTypeMapper::TypeTranslator *trans, // the type pointer
		SourceEmitter &emitter)
	{
		if (!trans->requires_translation_to_cpp()) {
			return var_name;
		}

		string translated_argument ("trans_" + var_name);
		trans->translate_to_cpp (var_name, translated_argument, emitter);
		return translated_argument;
	}

	/// Emit the translators for each argument. Return a list of the argument names that can
	/// be used to do the actual calls.
	vector<string> emit_cpp_args (const vector<RootClassMethodArg> &args, SourceEmitter &emitter)
	{
		vector<string> cpp_argnames;
		for (unsigned int i = 0; i < args.size(); i++) {
			const CPPNetTypeMapper::TypeTranslator *trans = CPPNetTypeMapper::instance()->get_translator_from_cpp (args[i].CPPTypeName());
			cpp_argnames.push_back(emit_translation_net_cpp(args[i].get_argname(), trans, emitter));
		}
		return cpp_argnames;
	}

	void emit_translation_net_cpp_cleanup (const string &arg_name, // Used in .NET world
		const string &cpp_name, // Used in C++ world
		const CPPNetTypeMapper::TypeTranslator *trans,
		SourceEmitter &emitter)
	{
		if (trans->requires_cleanup_code()) {
			trans->translate_to_cpp_cleanup (arg_name, cpp_name, emitter);
		}
	}

	/// Issue the cleanup calls for argument names
	void clean_up_args (const vector<RootClassMethodArg> &args,
		const vector<string> &cpp_argnames,
		SourceEmitter &emitter)
	{
		for (unsigned int i = 0; i < args.size(); i++) {
			const CPPNetTypeMapper::TypeTranslator *trans = CPPNetTypeMapper::instance()->get_translator_from_cpp (args[i].CPPTypeName());
			emit_translation_net_cpp_cleanup (args[i].get_argname(), cpp_argnames[i], trans, emitter);
		}
	}

	string clean_up_net_name(const string &name)
	{
		string result = name;
		for (int i = 0; i < result.size(); i++) {
			if (result[i] == '-')
				result[i] = '_';
			if (result[i] == '>')
				result[i] = '_';
		}
		return result;

	}

	/// Emit code to issue a "return" statement of some sort
	void emit_return (const CPPNetTypeMapper::TypeTranslator *return_translator, const std::string &return_var, SourceEmitter &emitter, bool use_interface = false, bool is_static = false)
	{
		string return_var_name (return_var);
		if (return_translator->requires_translation_to_net()) {
			auto dotnet_return_var = clean_up_net_name ("dotnet_" + return_var);
			return_translator->translate_to_net (dotnet_return_var, return_var, emitter, use_interface, is_static);
			return_var_name = dotnet_return_var;
		}
		emitter.start_line() << "return " << return_var_name << ";" << endl;
	}
}

///
/// Write out the body of a function!
///
void ClassTranslator::emit_function_body(const RootClassMethod &method, const RootClassInfo &info, SourceEmitter &emitter)
{
	///
	/// If we can't translate the method, we should bail out right away.
	///

	if (method.IsAmbiguous()) {
		emitter.start_line() << "throw gcnew ::System::NotImplementedException(\"Method has ambiguous C++ resolution: not currently supported.\");" << endl;
		return;
	} else if (method.IsHidden()) {
		emitter.start_line() << "throw gcnew ::System::NotImplementedException(\"Method has is protected in C++ class: can't be accessed.\");" << endl;
		return;
	}

	///
	/// Setup for return - we may not use it (this function may not demand it).
	///

	string return_var ("f_abz_result"); // Common (potential) name.

	///
	/// Translate the arguments into CPP land from .net land
	///

	const vector<RootClassMethodArg> &args = method.arguments();
	vector<string> cpp_argnames (emit_cpp_args(args, emitter));

	///
	/// Now that we have the arguments in hand, we can write the body of the function.
	///

	if (method.IsCtor()) {
		emitter.start_line() << "_instance = new ::" << info.CPPName() << "(";
		for (unsigned int i = 0; i < cpp_argnames.size(); i++) {
			if (i != 0) {
				emitter() << ", ";
			}
			emitter() << cpp_argnames[i];
		}
		emitter() << ");" << endl;

		// If this has a super-class, we need to set the instance there.
		auto superInfo (info.GetBestClassToInherrit());
		if (superInfo.size() != 0) {
			auto &superInfoPtr = RootClassInfoCollection::GetRootClassInfo(superInfo);
			emitter.start_line() << superInfoPtr.NETName() << "::SetInstance(_instance);" << endl;
		}

		emit_registration(info, emitter, true);
	} else {
		const CPPNetTypeMapper::TypeTranslator *return_translator = method.get_return_type_translator();
		if (return_translator != 0) {
			emitter.start_line() << return_translator->cpp_code_typename() << " " << return_var << " = ";
		} else {
			emitter.start_line();
		}

		/// If static, then make the static call
		if (method.IsStatic()) {
			emitter() << "::" << method.ClassOfMethodDefinition() << "::" << method.NETName();
		} else {
			if (method.IsConst()) {
				emitter() << "((const " << info.CPPName() << " *) _instance)->";
			} else {
				emitter() << "_instance->";
			}
			emitter() << method.FullName();
		}
		emitter() << "(";
		for (unsigned int i = 0; i < cpp_argnames.size(); i++) {
			if (i != 0) {
				emitter() << ", ";
			}
			emitter() << cpp_argnames[i];
		}
		emitter() << ");" << endl;
	}

	///
	/// Next, do any clean up required from the argument translation. I hope this is exception
	/// safe!!! (memory leaks bad!!).
	///

	clean_up_args (args, cpp_argnames, emitter);

	///
	/// If there is a return. 
	///

	if ((!method.IsAmbiguous() && !method.IsHidden()) && !method.IsCtor() && method.has_return_value()) {
		emit_return (method.get_return_type_translator(), return_var, emitter);
	}
}

namespace {
	// Get the operator out for a non-asignment operator ("operator+").
	string parse_nonassign_operator (const RootClassMethod &method)
	{
		auto name = method.NETName().substr(string("operator").length());
		return name;
	}
}

///
/// Generate the actual class.
///
void ClassTranslator::generate_class_methods (RootClassInfo &info, SourceEmitter &emitter)
{
	///
	/// Make sure that we are dealing with nullptr's that we can understand!
	///

	emitter() << "#ifdef nullptr" << endl;
	emitter() << "#undef nullptr" << endl;
	emitter() << "#endif" << endl;

	//
	// If this isn't a base class then we will need to reference other guys in the c-tors.
	//

	auto superClass = info.GetBestClassToInherrit();
	RootClassInfo *superClassInfo (nullptr);
	if (superClass.size() != 0) {
		superClassInfo = RootClassInfoCollection::GetRootClassInfoPtr(superClass);
	}

	///
	/// First, do our particular c-tors...
	///

	emitter.start_line() << info.NETName() << "::" << info.NETName() << "(::" << info.CPPName() << " *instance)" << endl;
	emitter.start_line() << " : _instance(instance)";
	if (superClassInfo != nullptr) {
		emitter() << ", " << superClassInfo->NETName() << "(_instance)";
	}
	emitter() << endl;
	emitter.brace_open();
	emit_registration(info, emitter, false);
	emitter.brace_close();

	emitter.start_line() << info.NETName() << "::" << info.NETName() << "(::" << info.CPPName() << " &instance)" << endl;
	emitter.start_line() << " : _instance(&instance)";
	if (superClassInfo != nullptr) {
		emitter() << ", " << superClassInfo->NETName() << "(_instance)";
	}
	emitter() << endl;
	emitter.brace_open();
	emit_registration(info, emitter, false);
	emitter.brace_close();

	///
	/// Drop this object from registration info
	///

	emitter.start_line() << "void " << info.NETName() << "::DropObjectFromTables (void)" << endl;
	emitter.brace_open();
	if (info.InheritsFromTObject() || info.CPPName() == "TObject") {
		emitter.start_line() << "ROOTNET::Utility::ROOTObjectManager::instance()->ForgetAboutObject(_instance);" << endl;
	}
	emitter.brace_close();


	///
	/// Do all the public methods, ctors and etc. that we need to get done!
	/// Some methods have the same signature, differing only by a "const" or
	/// similar. So we make sure we don't write those out twice.
	///

	set<string> written_methods;
	vector<RootClassMethod> arrayOperators;
	vector<RootClassMethod> mathOperators;
	const vector<RootClassMethod> &class_protos (info.GetAllPrototypesForThisClass(true));
	auto inh_classes(GetNonInherritedClasses(info));

	for (unsigned int i = 0; i < class_protos.size(); i++) {
		const RootClassMethod &method = class_protos[i];

		// Make sure this is a method we want to be implementing here!
		if (inh_classes.find(method.ClassOfMethodDefinition()) == inh_classes.end())
			continue;

		if (method.IsIndexer()) {
			arrayOperators.push_back(method);
			continue;
		}

		if (!method.IsGoodForClass()) {
			continue;
		}

		if (method.IsMathOperator()) {
			mathOperators.push_back(method);
			continue;
		}

		try {
			string n_header = method.generate_normalized_method_header();
			if (written_methods.find(n_header) != written_methods.end()) {
				continue;
			}
			written_methods.insert(n_header);

			if (method.has_return_value() && method.get_return_type_translator()->is_reference_to_object()) {
				continue;
			}

			emitter.start_line() << method.generate_method_header(true) << endl;

			if (method.IsCtor() && superClassInfo != nullptr) {
				emitter.start_line() << "  : " << superClassInfo->NETName() << " ((::" << superClassInfo->CPPName() << "*) nullptr)" << endl;
			}

			emitter.brace_open();
		} catch (runtime_error &e) {
			cout << "  translation failed (" << method.CPPName() << "): " << e.what() << endl;
			continue;
		}

		///
		/// Great. Now do the call to actually make the "stuff" happy
		///

		emit_function_body(method, info, emitter);

		///
		/// Done with the method
		///

		emitter.brace_close();
		emitter() << endl;
	}

	//
	// Do the math methods
	//

	for (vector<RootClassMethod>::const_iterator itr = mathOperators.begin(); itr != mathOperators.end(); itr++) {
		auto headers (generate_operator_header(*itr, true));
		for (vector<string>::const_iterator itr_h = headers.begin(); itr_h != headers.end(); itr_h++) {
			emitter.start_line() << *itr_h << endl;
			emitter.brace_open();

			// Get the CPP versions of the arguments
			const vector<RootClassMethodArg> &args = itr->arguments();
			vector<string> cpp_argnames (emit_cpp_args(args, emitter));

			// Now, do the calc
			auto op (parse_nonassign_operator(*itr));

			string return_var ("f_abc_return");
			const CPPNetTypeMapper::TypeTranslator *return_translator = itr->get_return_type_translator();
			if (return_translator != 0) {
				emitter.start_line() << return_translator->cpp_code_typename() << " " << return_var << " = ";
			} else {
				emitter.start_line();
			}

			if (cpp_argnames.size() == 0) { // Unary operator
				emitter() << op << " *(base_obj_a1->_instance)";
			} else { // Binary operator
				emitter() << "*(base_obj_a1->_instance) " << op << " " << cpp_argnames[0];
			}
			emitter() << ";" << endl;

			if (itr->has_return_value())
				emit_return (return_translator, return_var, emitter, false);

			emitter.brace_close();
			emitter() << endl;
		}
	}

	///
	/// Emit any extra features
	///

	FeatureManager::GetFeaturesFor(info).emit_class_methods(info, emitter);

	///
	/// Do the properties for this object.
	///

	const vector<RootClassProperty> &properties (info.GetProperties());
	for (vector<RootClassProperty>::const_iterator itr = properties.begin(); itr != properties.end(); itr++) {
		// Make sure at least one of these guys is defined in this thing

		if (!propertyShouldBeEmitted(*itr, inh_classes))
			continue;

		if (itr->isGetter()) {
			emitter.start_line() << itr->property_type() << " " << info.NETName() << "::" << itr->name() << "::get ()" << endl;
			emitter.brace_open();
			emit_function_body(*(itr->getter_method()), info, emitter);
			emitter.brace_close();
		}
		if (itr->isSetter()) {
			emitter.start_line() << "void " << info.NETName() << "::" << itr->name() << "::set (" << itr->property_type()
				<< " " << itr->setter_method()->arguments()[0].get_argname()  << ")" << endl;
			emitter.brace_open();
			emit_function_body(*(itr->setter_method()), info, emitter);
			emitter.brace_close();
		}
	}

	///
	/// Emit fields for this object. Symantics are a little tricky here in the following sense - a field can
	/// have only a single type for get/set. If we the two types aren't the same then we are a little bit stuck. So
	/// we prefer the 'get' over the setup. That usually works out in the ROOT world.
	///

	auto &fields (info.GetAllDataFields(true));
	for (int i = 0; i < fields.size(); i++) {
		const RootClassField &f(fields[i]);

		// Make sure this field is in the class we are working on here.
		if (inh_classes.find(f.ClassOfFieldDefinition()) == inh_classes.end())
			continue;

		if (f.GetterOK()) {
			emitter.start_line() << f.NETType() << " " << info.NETName() << "::" << f.NETName() << "::get ()" << endl;
			emitter.brace_open();
			emit_return(f.Translator(), "_instance->" + f.CPPName(), emitter, false, true);
			emitter.brace_close();
		}

		if (f.SetterOK()) {
			emitter.start_line() << "void " << info.NETName() << "::" << f.NETName()
				<< "::set (" << f.NETType() << " f_xyz_val)" << endl;
			emitter.brace_open();
			auto tempname (emit_translation_net_cpp("f_xyz_val", f.Translator(), emitter));
			emitter.start_line() << "    _instance->" << f.CPPName() << " = " << tempname << ";" << endl;
			emit_translation_net_cpp_cleanup("f_xyz_val", tempname, f.Translator(), emitter);
			emitter.brace_close();
		}


	}

	///
	/// Deal with the indexer methods. This is like above, only we know exactly what we are
	/// writing so we can move a little faster with fewer if statements. :-)
	///
	/// Indexers can suffer from covarient returns as well, so we need to double
	/// check which operator we are calling for indexing!
	///

	vector<CPPIndexerInfo> indexers (SortIndexers(arrayOperators));
	for (unsigned int i = 0; i < indexers.size(); i++) {
		CPPIndexerInfo &iinfo (indexers[i]);

		emitter.start_line() << iinfo._return_type->net_return_type_name() << " " << info.NETName() << "::default::get(" << iinfo._index_type->net_interface_name() << " index)" << endl;
		emitter.brace_open();
		string arg_name (emit_translation_net_cpp ("index", iinfo._index_type, emitter));
		string return_val ("f_abc_return");
		emitter.start_line() << iinfo._return_type->cpp_code_typename() << " " << return_val << " = ";
		if (iinfo._method->ClassOfMethodDefinition() != info.CPPName()) {
			emitter() << " _instance->" << iinfo._method->ClassOfMethodDefinition() << "::operator[](" << arg_name << ");" << endl;
		} else {
			emitter() << " (*_instance)[" << arg_name << "];" << endl;
		}

		if (!iinfo._index_type->clean_up_matters_for_return_value_only()) {
			emit_translation_net_cpp_cleanup ("index", arg_name, iinfo._index_type, emitter);
		}
		emit_return (iinfo._return_type, return_val, emitter);
		emitter.brace_close();

		if (iinfo._is_setter) {
			emitter.start_line() << "void " << info.NETName() << "::default::set(" << iinfo._index_type->net_interface_name() << " index, " << iinfo._return_type->net_return_type_name() << " value)" << endl;
			emitter.brace_open();
			string arg_name (emit_translation_net_cpp ("index", iinfo._index_type, emitter));
			string value_name (emit_translation_net_cpp ("value", iinfo._return_type, emitter));
			emitter.start_line() << "  (*_instance)[" << arg_name << "] = " << value_name << ";" << endl;
			if (!iinfo._index_type->clean_up_matters_for_return_value_only()) {
				emit_translation_net_cpp_cleanup ("index", arg_name, iinfo._index_type, emitter);
			}
			if (!iinfo._return_type->clean_up_matters_for_return_value_only()) {
				emit_translation_net_cpp_cleanup ("value", value_name, iinfo._return_type, emitter);
			}
			emitter.brace_close();
		}
	}

}

///
/// Check to see if there is a template in our past. If there is, we have to can doing this
/// particular class translation.
///
bool ClassTranslator::check_inheritance_list(const RootClassInfo &class_info)
{
	///
	/// One thing that is a little tricky is when a class has inherited from a template class. we can't deal with those
	/// currently.
	///

	const vector<string> inherited_classes = class_info.GetDirectInheritedClasses();
	for (unsigned int i = 0; i < inherited_classes.size(); i++) {
		if (inherited_classes[i].find("<") != inherited_classes[i].npos) {
			return false;
		}
	}

	///
	/// Ok -- good stuff!
	///

	return true;
}

///
/// If there are some classes that can be selectivly removed from the inheritance list to enable
/// translation, then do that!
///
void ClassTranslator::clean_inheritance_list(RootClassInfo &info)
{
	const vector<string> class_list (info.GetDirectInheritedClasses());
	for (unsigned int i = 0; i < class_list.size(); i++) {
		if (!CPPNetTypeMapper::instance()->has_mapping(class_list[i]))
		{
			info.RemoveInheritedClass(class_list[i]);
		}
	}
}

///
/// Returns the list of dependent library names for a particular library. Basically, all the other libraries that
/// were used to draw includes from during this translation process.
///
vector<string> ClassTranslator::get_dependent_libraries(const std::string &library_name) const
{
	map<string, set<string> >::const_iterator lib_info = _library_dependencies.find(library_name);
	if (lib_info == _library_dependencies.end()) {
		return vector<string> ();
	}
	set<string> set_of_libs(lib_info->second);
	vector<string> result (set_of_libs.begin(), set_of_libs.end());
	return result;
}

///
/// Return a list of library names
///
vector<string> ClassTranslator::get_all_library_names() const
{
	vector<string> result;
	transform(_library_dependencies.begin(), _library_dependencies.end(), back_inserter(result),
		[] (const pair<string, set<string> > &item) {return item.first;});

	return result;

}

///
/// Always emit the headers in .cpp file -- default implementation is one very large library! :-)
///
bool ClassTranslator::emit_this_header(const RootClassInfo &class_being_wrapped, const RootClassInfo &dependent_class)
{
	return true;
}

///
/// We will write out a seperate file for an enum as long as it isn't a class enum
///
bool ClassTranslator::emit_this_enum(const RootClassInfo &class_being_wrapped, const RootEnum &dependent_class)
{
	return true;
}

///
/// Load up globals
///
void ClassTranslator::load_globals(void)
{
	_globals_by_type = ROOTHelpers::GetAllGlobals();
}

///
/// Does this type have any globals?
///
bool ClassTranslator::type_has_globals (const std::string &type_name) const
{
	map<string, vector<RootGlobalVariable> >::const_iterator itr = _globals_by_type.find(type_name);
	return itr != _globals_by_type.end();
}


///
/// List of all the type names for a type
///
const vector<RootGlobalVariable> &ClassTranslator::list_of_globals_of_type(const std::string &type_name) const
{
	map<string, vector<RootGlobalVariable> >::const_iterator itr = _globals_by_type.find(type_name);
	if (itr == _globals_by_type.end()) {
		static vector<RootGlobalVariable> bogus;
		return bogus;
	}
	return itr->second;
}

///
/// Translate an enum
///
void ClassTranslator::translate(RootEnum &enum_info)
{
	ostringstream hpp_filename;
	hpp_filename << _base_directory << "\\" << enum_info.NameUnqualified() << ".hpp";

	SourceEmitter hpp_emitter (hpp_filename.str());
	hpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
	hpp_emitter() << "#pragma once" << endl;

	hpp_emitter.start_namespace ("ROOTNET");

	write_header_enum_standard (enum_info, hpp_emitter, true);

	hpp_emitter.brace_close();
	hpp_emitter.close();

	ostringstream cpp_filename;
	cpp_filename << _base_directory << "\\" << enum_info.NameUnqualified() << ".cpp";

	SourceEmitter cpp_emitter (cpp_filename.str());
	cpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
	cpp_emitter.include_file(enum_info.NameUnqualified() + ".hpp");
	cpp_emitter.close();
}

namespace
{
	//
	// Write out a single class for a global variable. yeah, I know, but at least it is totally
	// consistent and thus easy to find.
	//
	void write_header_global_variable (const CPPNetTypeMapper::TypeTranslator *trans, const RootGlobalVariable &global, SourceEmitter &hpp_emitter)
	{
		hpp_emitter.start_line() << endl;
		hpp_emitter.start_line() << "// " << trans->cpp_code_typename() << " " << global.Name() << endl;
		hpp_emitter.start_line() << "public ref class " << global.Name() << endl;
		hpp_emitter.brace_open();
		hpp_emitter.start_line() << "public:" << endl;
		hpp_emitter.start_line() << "static property " << trans->net_interface_name() << " Value" << endl;
		hpp_emitter.brace_open();

		// Do the get.
		hpp_emitter.start_line() << trans->net_interface_name()  << " get()" << endl;
		hpp_emitter.brace_open();
		if (trans->requires_translation())
		{
			trans->translate_to_net("result", "::" + global.Name(), hpp_emitter);
			hpp_emitter.start_line() << "return result;" << endl;
		} else {
			hpp_emitter.start_line() << "return " << "::" << global.Name() << ";" << endl;
		}
		hpp_emitter.brace_close();

		hpp_emitter.start_line() << "void set(" << trans->net_interface_name() << " v)" << endl;
		hpp_emitter.brace_open();
		if (trans->requires_translation())
		{
			trans->translate_to_cpp("v", "cpp_v", hpp_emitter);
			hpp_emitter.start_line() << "::" << global.Name() << " = cpp_v;" << endl;
		} else {
			hpp_emitter.start_line() << "::" << global.Name() << " = v;" << endl;
		}
		hpp_emitter.brace_close();

		hpp_emitter.brace_close();
		hpp_emitter.brace_close(true);
	}
}

///
/// Generate a file that contains all the globals that
/// we know about.
///
void ClassTranslator::translate_global_variables(const string &libname)
{
	//
	// Get the list of global variables we are going to work with.
	//

	vector<RootGlobalVariable> vars;
	for_each(_globals_by_type.begin(), _globals_by_type.end(), [&] (const pair<string, vector<RootGlobalVariable> > &global_list)
	{
		auto &myvars (vars);
		auto &mylibname (libname);
		for_each(global_list.second.begin(), global_list.second.end(), [&] (const RootGlobalVariable &global)
		{
			if (CPPNetTypeMapper::instance()->has_mapping(global.Type()) && (mylibname == "*" || mylibname == global.LibName()))
			{
				myvars.push_back(global);
			}
		});
	});

	//
	// Generate one header, and its matching cpp file.
	//

	ostringstream hpp_filename;
	hpp_filename << _base_directory << "\\Globals.hpp";

	SourceEmitter hpp_emitter (hpp_filename.str());
	hpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
	hpp_emitter() << "#pragma once" << endl;

	//
	// Now include the header files we need to do this translation. There are two sets of headers we have to include.
	//

	set<string> requested_includes;
	for_each (vars.begin(), vars.end(), [&requested_includes] (const RootGlobalVariable &global)
	{
		auto includes = global.GetListOfIncludeFiles();
		for (int i = 0; i < includes.size(); i++) {
			requested_includes.insert(includes[i]);
		}
	});

	for_each(requested_includes.begin(), requested_includes.end(), [&hpp_emitter] (const string &include)
	{
		hpp_emitter.include_file(include);
	});

	//
	// We want a "special" namespace for all of this.
	//

	hpp_emitter.start_namespace ("ROOTNET");
	hpp_emitter.start_namespace ("Globals");

	//
	// Now loop through all of the types in there. Only do types we
	// know how to deal with.
	//

	for_each(vars.begin(), vars.end(), [&hpp_emitter] (const RootGlobalVariable &global)
	{
		auto translator = CPPNetTypeMapper::instance()->get_translator_from_cpp(global.Type());
		write_header_global_variable(translator, global, hpp_emitter);
	});

	hpp_emitter.brace_close();
	hpp_emitter.brace_close();
	hpp_emitter.close();

	//
	// Since everything is defined in the hpp file, we just deal with it
	// there. This is a .cpp file that is only necessary to include in the
	// build so that the .hpp file gets correctly sucked in.
	//

	ostringstream cpp_filename;
	cpp_filename << _base_directory << "\\Globals.cpp";
	SourceEmitter cpp_emitter (cpp_filename.str());
	cpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
	cpp_emitter.include_file("Globals.hpp");
	cpp_emitter.close();
}
